/****************************************************
	文件：CustomShaderGUI.cs
	作者：HuskyT
	邮箱：1005240602@qq.com
	日期：2020/9/14 14:43:59
	功能：自定义 Shader 材质面板 UI
*****************************************************/

using System;
using UnityEditor;
using UnityEngine;
using UnityEngine.Rendering;

public class CustomShaderGUI : ShaderGUI
{
    /// <summary>
    /// 材质编辑器
    /// </summary>
    private MaterialEditor mEditor;
    /// <summary>
    /// 材质对象 数组（以此支持一次性修改多个 Object 的 Material）
    /// </summary>
    private UnityEngine.Object[] mMats;
    /// <summary>
    /// 材质属性 数组
    /// </summary>
    private MaterialProperty[] mProperties;

    private bool mShowPreset;

    /// <summary>
    /// Alpha裁剪
    /// </summary>
    private bool Clipping
    {
        set => SetProperty("_Clipping", "_CLIPPING", value);
    }
    /// <summary>
    /// 预乘Alpha（透明物体Diffuse因透光产生亮度衰减）
    /// </summary>
    private bool PremultiplyAlpha
    {
        set => SetProperty("_PremultiplyAlpha", "_PREMULTIPLY_ALPHA", value);
    }
    /// <summary>
    /// 源混合因子（与当前像素颜色相乘）
    /// </summary>
    private BlendMode SrcBlend
    {
        set => SetProperty("_SrcBlend", (float)value);
    }
    /// <summary>
    /// 目标混合因子（与颜色缓冲中的颜色值相乘）
    /// </summary>
    private BlendMode DstBlend
    {
        set => SetProperty("_DstBlend", (float)value);
    }
    /// <summary>
    /// 是否开启深度写入
    /// </summary>
    private bool ZWrite
    {
        set => SetProperty("_ZWrite", value ? 1f : 0f);
    }
    /// <summary>
    /// 渲染模式
    /// </summary>
    private RenderQueue RenderQueue
    {
        set
        {
            foreach (Material mat in mMats)
            {
                mat.renderQueue = (int)value;
            }
        }
    }

    private bool HasProperty(string name)
    {
        return FindProperty(name, mProperties, false) != null;
    }

    private bool HasPremultiplyAlpha => HasProperty("_PremulAlpha");

    public override void OnGUI(MaterialEditor materialEditor, MaterialProperty[] properties)
    {
        base.OnGUI(materialEditor, properties);
        mEditor = materialEditor;
        mMats = materialEditor.targets;
        mProperties = properties;

        EditorGUILayout.Space();
        mShowPreset = EditorGUILayout.Foldout(mShowPreset, "Presets（预置模式）", true);
        if (mShowPreset)
        {
            OpaquePreset();
            ClipPreset();
            FadePreset();
            TransparentPreset();
        }
    }

    /// <summary>
    /// 不透明物体
    /// </summary>
    private void OpaquePreset()
    {
        if (PresetButton("Opaque"))
        {
            Clipping = false;
            PremultiplyAlpha = false;
            SrcBlend = BlendMode.One;
            DstBlend = BlendMode.Zero;
            ZWrite = true;
            RenderQueue = RenderQueue.Geometry;
        }
    }
    /// <summary>
    /// Alpha裁剪
    /// </summary>
    private void ClipPreset()
    {
        if (PresetButton("Clip"))
        {
            Clipping = true;
            PremultiplyAlpha = false;
            SrcBlend = BlendMode.One;
            DstBlend = BlendMode.Zero;
            ZWrite = true;
            RenderQueue = RenderQueue.AlphaTest;
        }
    }
    /// <summary>
    /// 褪色
    /// </summary>
    private void FadePreset()
    {
        if (PresetButton("Fade"))
        {
            Clipping = false;
            PremultiplyAlpha = false;
            SrcBlend = BlendMode.SrcAlpha;
            DstBlend = BlendMode.OneMinusSrcAlpha;
            ZWrite = false;
            RenderQueue = RenderQueue.Transparent;
        }
    }
    /// <summary>
    /// 透明物体
    /// </summary>
    private void TransparentPreset()
    {
        if (HasPremultiplyAlpha && PresetButton("Transparent"))
        {
            Clipping = false;
            PremultiplyAlpha = true;
            SrcBlend = BlendMode.One;
            DstBlend = BlendMode.OneMinusSrcAlpha;
            ZWrite = false;
            RenderQueue = RenderQueue.Transparent;
        }
    }

    /// <summary>
    /// 设置指定属性的属性值
    /// </summary>
    /// <param name="name">属性名称</param>
    /// <param name="value">属性值</param>
    private bool SetProperty(string name, float value)
    {
        MaterialProperty property = FindProperty(name, mProperties, false);
        if (property != null)
        {
            property.floatValue = value;
            return true;
        }
        return false;
    }
    /// <summary>
    /// 设置Toggle属性
    /// </summary>
    /// <param name="name"></param>
    /// <param name="keyword"></param>
    /// <param name="value"></param>
    private void SetProperty(string name, string keyword, bool value)
    {
        if (SetProperty(name, value ? 1f : 0f))
        {
            SetKeyword(keyword, value);
        }
    }
    /// <summary>
    /// 设置 Keyword
    /// </summary>
    /// <param name="keyword"></param>
    /// <param name="enabled"></param>
    private void SetKeyword(string keyword, bool enabled)
    {
        if (enabled)
        {
            foreach (Material mat in mMats)
            {
                mat.EnableKeyword(keyword);
            }
        }
        else
        {
            foreach (Material mat in mMats)
            {
                mat.DisableKeyword(keyword);
            }
        }
    }

    /// <summary>
    /// 预置 按钮
    /// </summary>
    /// <param name="name">按钮名</param>
    /// <returns></returns>
    private bool PresetButton(string name)
    {
        if (GUILayout.Button(name))
        {
            mEditor.RegisterPropertyChangeUndo(name); //保存点击数据
            return true;
        }
        return false;
    }
}
